/*******************************************************************************
 * Copyright (c) 2008 Sylvain Sicard.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Lesser Public License v2.1
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 * 
 * Contributors:
 *     Sylvain Sicard - initial API and implementation
 ******************************************************************************/
package fr.jade.fraclite.orb;

import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;

import org.objectweb.fractal.api.Interface;
import org.objectweb.fractal.api.type.InterfaceType;

import fr.jade.fraclite.orb.api.Binder;
import fr.jade.fraclite.orb.api.Name;
import fr.jade.fraclite.orb.names.TcpIpName;

/**
 * A skeleton gives access to a local interface of a Fractal
 * component. It unmarshalls invocation messages and calls the corresponding
 * methods on the local interface to which it gives access. Like stubs, a
 * skeleton gives access to the "functional" interface provided by a server
 * interface, and also gives access to the methods of the {@link Interface}
 * interface implemented by this server interface.
 */

public class UnicastSkeleton implements Skeleton {

  /**
   * The local server interface to which this skeleton gives access.
   */

  protected Map<Long,Object> targets;

  protected Binder binder;
  
  protected ServerSocket ss;
  
  protected ExecutorService es;
  
  /**
   * Constructs a new {@link UnicastSkeleton}.
   * @throws IOException 
   */
  public UnicastSkeleton (ExecutorService es, Binder binder, int port) throws IOException {
    targets = new HashMap<Long,Object>();
    this.binder = binder;
    this.ss = new ServerSocket(port);
    this.es = es;
  }
  
  public void registerTarget(Object target){
    long itfId = ((Interface)target).getFcItfGUId();
    //System.out.println("[skel] register "+itfId);
    targets.put(itfId, target);
  }
  
  public Name getName(Object target){
    long itfId = ((Interface)target).getFcItfGUId();
    String signature = ((InterfaceType)((Interface)target).getFcItfType()).getFcItfSignature();
    String host = null;
    try {
      host = InetAddress.getLocalHost().getHostName();
    } catch (UnknownHostException e) {
      e.printStackTrace();
    }
    int port = ss.getLocalPort();
    return new TcpIpName(itfId, signature, binder, host, port);
  }
  
  public void run(){
    try{
      while(true){
        Socket s = ss.accept();
        es.execute(new SkeletonTask(s, targets, binder));
      }   
    }catch(Exception e){
      e.printStackTrace();
    }
  }
  
  @Override
  public void finalize(){
    try{
      ss.close();
    }catch(IOException ignored){}
  }
}
